package com.boss.salary.parsingExcel.impl;

import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.boss.asset.service.IAssetInfoService;
import com.boss.salary.ExcelModel.ExcelResult;
import com.boss.salary.ExcelModel.PersonOperateModel;
import com.boss.salary.constant.ApiElementConstant;
import com.boss.salary.entity.PersonOperate;
import com.boss.salary.enums.PersonStateEnum;
import com.boss.salary.enums.PersonTypeEnum;
import com.boss.salary.enums.SalaryTypeEnum;
import com.boss.salary.enums.YesOrNoEnum;
import com.boss.salary.parsingExcel.ExcelParsingService;
import com.boss.sys.ca.user.dto.UserDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * <br>Title:
 * <br>Description:
 * <br>Author:
 * <br>Date:
 */
@Service("personExcelParsingServiceImpl")
public class PersonExcelParsingServiceImpl implements ExcelParsingService {

    @Autowired
    private IAssetInfoService assetInfoService;

    @Override
    public <E> ExcelResult<E> readExcelWithModel(InputStream inputStream, Class<? extends BaseRowModel> clazz, ExcelTypeEnum excelTypeEnum, UserDTO userDto) {
        // 性别
        List<Map<String, String>> sexList = assetInfoService.getBaseDataSelect(ApiElementConstant.SEX, ApiElementConstant.PROVINCE);
        // 民族
        List<Map<String, String>> natList = assetInfoService.getBaseDataSelect(ApiElementConstant.NAT, ApiElementConstant.PROVINCE);
        // 证件类型
        List<Map<String, String>> citTypeList = assetInfoService.getBaseDataSelect(ApiElementConstant.CITTYPE, ApiElementConstant.PROVINCE);
        // 学历
        List<Map<String, String>> schrecList = assetInfoService.getBaseDataSelect(ApiElementConstant.SCHREC, ApiElementConstant.PROVINCE);
        // 职务
        List<Map<String, String>> posgrList = assetInfoService.getBaseDataSelect(ApiElementConstant.POSGR, ApiElementConstant.PROVINCE);
        // 职级
        List<Map<String, String>> grList = assetInfoService.getBaseDataSelect(ApiElementConstant.GR, ApiElementConstant.PROVINCE);
        // 技术等级
        List<Map<String, String>> tecgrList = assetInfoService.getBaseDataSelect(ApiElementConstant.TECGR, ApiElementConstant.PROVINCE);
        // 工资级别
        List<Map<String, String>> salagrList = assetInfoService.getBaseDataSelect(ApiElementConstant.SALAGR, ApiElementConstant.PROVINCE);
        // 工资卡开户银行
        List<Map<String, String>> salbankList = assetInfoService.getBaseDataSelect(ApiElementConstant.SALBANK, userDto.getProvince());
        // 国籍
        List<Map<String, String>> nationalityList = assetInfoService.getBaseDataSelect(ApiElementConstant.NATIONALITY, ApiElementConstant.PROVINCE);
        // 人员身份
        List<Map<String, String>> perideList = assetInfoService.getBaseDataSelect(ApiElementConstant.PERIDE, ApiElementConstant.PROVINCE);
        // 经费保障方式
        List<Map<String, String>> fundmodeList = assetInfoService.getBaseDataSelect(ApiElementConstant.FUNDMODE, ApiElementConstant.PROVINCE);
        // 调用listener
        PersonExcelParsingListener listener = new PersonExcelParsingListener(sexList, natList, citTypeList, schrecList,
                posgrList, grList, tecgrList, salagrList, salbankList, nationalityList, perideList, fundmodeList);
        ExcelReader excelReader = new ExcelReader(inputStream, excelTypeEnum, null, listener);
        //默认只有一列表头
        excelReader.read(new Sheet(1, 1, clazz));
        List<PersonOperate> list = listener.getSuccessList();
        List<List<String>> errorList = listener.getErrorAllList();
        ExcelResult<PersonOperate> excelResult = new ExcelResult();
        excelResult.setSuccessList(list);
        excelResult.setErrorList(errorList);
        return (ExcelResult<E>) excelResult;
    }


    /**
     * excel解析
     * @param
     */
    private class PersonExcelParsingListener extends AnalysisEventListener<PersonOperateModel> {

        private final String timePattern = "yyyy-MM-dd";

        // 性别
        private List<Map<String, String>> sexList = null;
        // 民族
        private List<Map<String, String>> natList = null;
        // 证件类型
        private List<Map<String, String>> citTypeList = null;
        // 学历
        private List<Map<String, String>> schrecList = null;
        // 职务
        private List<Map<String, String>> posgrList = null;
        // 职级
        private List<Map<String, String>> grList = null;
        // 技术等级
        private List<Map<String, String>> tecgrList = null;
        // 工资级别
        private List<Map<String, String>> salagrList = null;
        // 工资卡开户银行
        private List<Map<String, String>> salbankList = null;
        // 国籍
        private List<Map<String, String>> nationalityList = null;
        // 人员身份
        private List<Map<String, String>> perideList = null;
        // 经费保障方式
        private List<Map<String, String>> fundmodeList = null;

        public PersonExcelParsingListener(List<Map<String, String>> sexList, List<Map<String, String>> natList,
                                          List<Map<String, String>> citTypeList, List<Map<String, String>> schrecList,
                                          List<Map<String, String>> posgrList, List<Map<String, String>> grList,
                                          List<Map<String, String>> tecgrList, List<Map<String, String>> salagrList,
                                          List<Map<String, String>> salbankList, List<Map<String, String>> nationalityList,
                                          List<Map<String, String>> perideList, List<Map<String, String>> fundmodeList) {
            this.sexList = sexList;
            this.natList = natList;
            this.citTypeList = citTypeList;
            this.schrecList = schrecList;
            this.posgrList = posgrList;
            this.grList = grList;
            this.tecgrList = tecgrList;
            this.salagrList = salagrList;
            this.salbankList = salbankList;
            this.nationalityList = nationalityList;
            this.perideList = perideList;
            this.fundmodeList = fundmodeList;
        }

        /** 成功list **/
        private List<PersonOperate> successList = new ArrayList<>();
        /** 失败list **/
        private List<List<String>> errorAllList = new ArrayList<>();

        @Override
        public void invoke(PersonOperateModel object, AnalysisContext analysisContext) {
            PersonOperate personOperate = new PersonOperate();
            List<String> errorList = new ArrayList<>(10);
            String errorMsg = "第"+analysisContext.getCurrentRowNum()+"行， %s值错误";
            // 人员状态 必填
            Object state = object.getState();
            // 如果为空，证明该行数据为空，直接返回
            if (StringUtils.isEmpty(state)) {
                return;
            }
            String stateCode = PersonStateEnum.valueOfName(state.toString());
            if (StringUtils.isEmpty(stateCode)) {
                errorList.add(String.format(errorMsg, "人员状态"));
            } else {
                personOperate.setState(stateCode);
            }
            // 工资类别
            Object meritPay = object.getMeritPayCode();
            if (!StringUtils.isEmpty(meritPay)) {
                String meritPayCode = SalaryTypeEnum.valueOfName(meritPay.toString());
                if (!StringUtils.isEmpty(meritPayCode)) {
                    personOperate.setMeritPayCode(meritPayCode);
                } else {
                    errorList.add(String.format(errorMsg, "工资类别"));
                }
            }
            // 姓名 必填
            Object personName = object.getPersonName();
            if (!StringUtils.isEmpty(personName)) {
                personOperate.setPersonName(personName.toString());
            } else {
                errorList.add(String.format(errorMsg, "姓名"));
            }
            // 性别
            Object sex = object.getSexCode();
            if (!StringUtils.isEmpty(sex)) {
                // 判断基础数据中是否包含读取到的值
                String code = getCodeByName(sexList, sex.toString());
                if (!StringUtils.isEmpty(code)) {
                    personOperate.setSexCode(code);
                } else {
                    errorList.add(String.format(errorMsg, "性别"));
                }
            }
            // 民族
            Object natCode = object.getNatCode();
            if (!StringUtils.isEmpty(natCode)) {
                // 判断基础数据中是否包含读取到的值
                String code = getCodeByName(natList, natCode.toString());
                if (!StringUtils.isEmpty(code)) {
                    personOperate.setNatCode(code);
                } else {
                    errorList.add(String.format(errorMsg, "民族"));
                }
            }
            // 证件类型 必填
            Object idenTypeCode = object.getIdenTypeCode();
            if (!StringUtils.isEmpty(idenTypeCode)) {
                // 判断基础数据中是否包含读取到的值
                String code = getCodeByName(citTypeList, idenTypeCode.toString());
                if (!StringUtils.isEmpty(code)) {
                    personOperate.setIdenTypeCode(code);
                } else {
                    errorList.add(String.format(errorMsg, "证件类型"));
                }
            } else {
                errorList.add(String.format(errorMsg, "证件类型"));
            }
            // 证件号码 必填
            Object idenNo = object.getIdenNo();
            if (!StringUtils.isEmpty(idenNo)) {
                personOperate.setIdenNo(idenNo.toString());
            } else {
                errorList.add(String.format(errorMsg, "证件号码"));
            }
            // 出生日期
            Object birthday = object.getBirthday();
            if (!StringUtils.isEmpty(birthday)) {
                try {
                    DateTimeFormatter dtf = DateTimeFormatter.ofPattern(timePattern);
                    LocalDateTime parse = LocalDateTime.parse(birthday.toString(), dtf);
                    personOperate.setBirthday(parse.toString());
                } catch (Exception e) {
                    errorList.add(String.format(errorMsg, "出生日期"));
                }
            }
            // 学历
            Object schRecCode = object.getSchRecCode();
            if (!StringUtils.isEmpty(schRecCode)) {
                // 判断基础数据中是否包含读取到的值
                String code = getCodeByName(schrecList, schRecCode.toString());
                if (!StringUtils.isEmpty(code)) {
                    personOperate.setSchRecCode(code);
                } else {
                    errorList.add(String.format(errorMsg, "学历"));
                }
            }
            // 人员类型
            Object personType = object.getPersonTypeCode();
            if (!StringUtils.isEmpty(personType)) {
                String personTypeCode = PersonTypeEnum.valueOfName(personType.toString());
                if (!StringUtils.isEmpty(personTypeCode)) {
                    personOperate.setPersonTypeCode(personTypeCode);
                } else {
                    errorList.add(String.format(errorMsg, "人员类型"));
                }
            }
            // 家庭地址
            Object personAddress = object.getPersonAddress();
            if (!StringUtils.isEmpty(personAddress)) {
                personOperate.setPersonAddress(personAddress.toString());
            }
            // 是否在编
            Object isAuth = object.getIsAuth();
            if (!StringUtils.isEmpty(isAuth)) {
                String isAuthCode = YesOrNoEnum.valueOfName(isAuth.toString());
                if (!StringUtils.isEmpty(isAuthCode)) {
                    personOperate.setIsAuth(Integer.parseInt(isAuthCode));
                } else {
                    errorList.add(String.format(errorMsg, "是否在编"));
                }
            }
            // 参加工作时间
            Object workInitDate = object.getWorkInitDate();
            if (!StringUtils.isEmpty(workInitDate)) {
                try {
                    DateTimeFormatter dtf = DateTimeFormatter.ofPattern(timePattern);
                    LocalDateTime parse = LocalDateTime.parse(workInitDate.toString(), dtf);
                    personOperate.setWorkInitDate(parse.toString());
                } catch (Exception e) {
                    errorList.add(String.format(errorMsg, "参加工作时间"));
                }
            }
            // 进入本单位时间
            Object enterAgencyDate = object.getEnterAgencyDate();
            if (!StringUtils.isEmpty(enterAgencyDate)) {
                try {
                    DateTimeFormatter dtf = DateTimeFormatter.ofPattern(timePattern);
                    LocalDateTime parse = LocalDateTime.parse(enterAgencyDate.toString(), dtf);
                    personOperate.setEnterAgencyDate(parse.toString());
                } catch (Exception e) {
                    errorList.add(String.format(errorMsg, "进入本单位时间"));
                }
            }
            // 职务
            Object posCode = object.getPosCode();
            if (!StringUtils.isEmpty(posCode)) {
                // 判断基础数据中是否包含读取到的值
                String code = getCodeByName(posgrList, posCode.toString());
                if (!StringUtils.isEmpty(code)) {
                    personOperate.setPosCode(code);
                } else {
                    errorList.add(String.format(errorMsg, "职务"));
                }
            }
            // 职级
            Object grCode = object.getGrCode();
            if (!StringUtils.isEmpty(grCode)) {
                // 判断基础数据中是否包含读取到的值
                String code = getCodeByName(grList, grCode.toString());
                if (!StringUtils.isEmpty(code)) {
                    personOperate.setGrCode(code);
                } else {
                    errorList.add(String.format(errorMsg, "职级"));
                }
            }
            // 技术等级
            Object tecGrCode = object.getTecGrCode();
            if (!StringUtils.isEmpty(tecGrCode)) {
                // 判断基础数据中是否包含读取到的值
                String code = getCodeByName(tecgrList, tecGrCode.toString());
                if (!StringUtils.isEmpty(code)) {
                    personOperate.setTecGrCode(code);
                } else {
                    errorList.add(String.format(errorMsg, "技术等级"));
                }
            }
            // 工资级别
            Object salaGrCode = object.getSalaGrCode();
            if (!StringUtils.isEmpty(salaGrCode)) {
                // 判断基础数据中是否包含读取到的值
                String code = getCodeByName(salagrList, salaGrCode.toString());
                if (!StringUtils.isEmpty(code)) {
                    personOperate.setSalaGrCode(code);
                } else {
                    errorList.add(String.format(errorMsg, "工资级别"));
                }
            }
            // 工资卡开户银行
            // TODO 找单位设置的银行
            Object salaCardBank = object.getSalaCardBank();
            if (!StringUtils.isEmpty(salaCardBank)) {
                // 判断基础数据中是否包含读取到的值
                String code = getCodeByName(salbankList, salaCardBank.toString());
                if (!StringUtils.isEmpty(code)) {
                    personOperate.setSalaGrCode(code);
                } else {
                    errorList.add(String.format(errorMsg, "工资卡开户银行"));
                }
            }
            // 工资卡卡号
            Object salaCardNo = object.getSalaCardNo();
            if (!StringUtils.isEmpty(salaCardNo)) {
                personOperate.setPersonAddress(salaCardNo.toString());
            }
            // 生效时间
            Object startDate = object.getStartDate();
            if (!StringUtils.isEmpty(startDate)) {
                try {
                    DateTimeFormatter dtf = DateTimeFormatter.ofPattern(timePattern);
                    LocalDateTime parse = LocalDateTime.parse(startDate.toString(), dtf);
                    personOperate.setStartDate(parse.toString());
                } catch (Exception e) {
                    errorList.add(String.format(errorMsg, "生效时间"));
                }
            }
            // 国籍
            Object nation = object.getNation();
            if (!StringUtils.isEmpty(nation)) {
                // 判断基础数据中是否包含读取到的值
                String code = getCodeByName(nationalityList, nation.toString());
                if (!StringUtils.isEmpty(code)) {
                    personOperate.setNation(code);
                } else {
                    errorList.add(String.format(errorMsg, "国籍"));
                }
            }
            // 人员身份
            Object personIdeCode = object.getPersonIdeCode();
            if (!StringUtils.isEmpty(personIdeCode)) {
                // 判断基础数据中是否包含读取到的值
                String code = getCodeByName(perideList, personIdeCode.toString());
                if (!StringUtils.isEmpty(code)) {
                    personOperate.setPersonIdeCode(code);
                } else {
                    errorList.add(String.format(errorMsg, "人员身份"));
                }
            }
            // 经费保障方式
            Object fundmode = object.getFundmode();
            if (!StringUtils.isEmpty(fundmode)) {
                // 判断基础数据中是否包含读取到的值
                String code = getCodeByName(fundmodeList, fundmode.toString());
                if (!StringUtils.isEmpty(code)) {
                    personOperate.setFundmode(code);
                } else {
                    errorList.add(String.format(errorMsg, "经费保障方式"));
                }
            }
            // 是否特殊岗位
            Object isSpecialPost = object.getIsSpecialPost();
            if (!StringUtils.isEmpty(isSpecialPost)) {
                String isSpecialPostCode = YesOrNoEnum.valueOfName(isSpecialPost.toString());
                if (!StringUtils.isEmpty(isSpecialPostCode)) {
                    personOperate.setIsAuth(Integer.parseInt(isSpecialPostCode));
                } else {
                    errorList.add(String.format(errorMsg, "是否特殊岗位"));
                }
            }
            // 离休时间
            Object retireDate = object.getRetireDate();
            if (!StringUtils.isEmpty(retireDate)) {
                try {
                    DateTimeFormatter dtf = DateTimeFormatter.ofPattern(timePattern);
                    LocalDateTime parse = LocalDateTime.parse(retireDate.toString(), dtf);
                    personOperate.setRetireDate(parse.toString());
                } catch (Exception e) {
                    errorList.add(String.format(errorMsg, "离休时间"));
                }
            }
            // 如果没有错误，成功列表中增加数据
            if (errorList.size() == 0) {
                successList.add(personOperate);
            } else {
                errorAllList.add(errorList);
            }
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {

        }

        public List<PersonOperate> getSuccessList() {
            return successList;
        }

        public void setSuccessList(List<PersonOperate> successList) {
            this.successList = successList;
        }

        public List<List<String>> getErrorAllList() {
            return errorAllList;
        }

        public void setErrorList(List<List<String>> errorAllList) {
            this.errorAllList = errorAllList;
        }
    }


    /**
     * List<Map<String, String>> 中，根据name找code
     * @param list
     * @return
     */
    private String getCodeByName(List<Map<String, String>> list, String name) {
        String code = "";
        for (Map<String, String> map: list) {
            for (Map.Entry<String, String> entry : map.entrySet()) {
                if (entry.getValue().equals(name)) {
                    code = entry.getKey();
                    break;
                }
            }
            if (!"".equals(code)) {
                break;
            }
        }
        return code;
    }
}
